package com.skylink.gaea.common.tree;

import java.util.*;

/**
 * tree 模型工具类
 * 支持 list、tree、map 等村节点在各种数据结构中的转换。
 *
 * @author zeno
 */
public class TreeUtils{

  /**
   * list 转换成 tree
   *
   * @param nodes list 节点
   *
   * @return tree 结构模型
   */
  public static <ID> List<Node<ID>> convertListToTree( List<Node<ID>> nodes ){

    Map<ID,Node<ID>> nodeMap = TreeUtils.convertToMap(nodes);
    Set<Map.Entry<ID,Node<ID>>> entries = nodeMap.entrySet();
    List<Node<ID>> trees = new LinkedList<>();

    for(Map.Entry<ID,Node<ID>> entry : entries){

      Node<ID> value = entry.getValue();
      ID parentId = value.getParentId();
      if( Objects.isNull(parentId) ){
        // parentId 为 null 表示顶级节点，加入到树列表中。
        trees.add(value);
      }
      else{
        Node<ID> parentNode = nodeMap.get(parentId);
        if( parentNode != null ){
          parentNode.addChild(value);
        }
      }
    }

    return trees;
  }

  /**
   * 将 tree 转换成 map
   *
   * @param treeNodes
   * @param <ID>      节点 ID
   *
   * @return list 结构
   */
  public static <ID> List<Node<ID>> convertTreeToList( Collection<Node<ID>> treeNodes ){

    List<Node<ID>> list = new ArrayList<>(treeNodes);
    for(int i = 0; i < list.size(); ++i){
      Node<ID> node = list.get(i);
      if( !node.getChildren().isEmpty() ){
        list.addAll(node.getChildren());
      }
    }

    return list;
  }

  /**
   * 将 list 或 tree 转换成 map
   *
   * @param nodes list 或 tree 节点
   * @param <ID>  节点ID
   *
   * @return ID map
   */
  public static <ID> Map<ID,Node<ID>> convertToMap( Collection<Node<ID>> nodes ){

    List<Node<ID>> nodeList = new ArrayList<>(nodes);
    // 命用 TreeMap ，为 ID 进行排序
    Map<ID,Node<ID>> treeNodeMap = new TreeMap<>();
    for(int i = 0; i < nodeList.size(); ++i){
      Node<ID> node = nodeList.get(i);
      treeNodeMap.put(node.getId(), node);

      if( node.getChildren().isEmpty() ){
        continue;
      }

      // 将子节点加入到集合尾部，用于继续遍历
      nodeList.addAll(node.getChildren());
    }

    return treeNodeMap;
  }
}

